<?php

namespace app\result;


use app\model\TimerQueue;

class TimeQueueResult extends BaseResult
{

    public function __construct()
    {
        parent::__construct();
        $this->model = new TimerQueue();
    }

    //执行任务
    public function do_job($id)
    {
        bs_log($id, 'do_job', 'queue_diy_task.log');
        $ckey = md5('queue_diy_task' . $id);
        if (cache($ckey)) {
            return data_return_arr('有任务在执行');
        }
        if (!$id) {
            return data_return_arr('参数错误');
        }
        cache($ckey, 1, 5);

        $model = new TimerQueue();
        $item = $model->data_get(['id' => $id]);
        if (!$item) {
            return data_return_arr('任务不存在');
        }
        if ($item['status'] == 1) {
            return data_return_arr('任务已执行', 0);
        }
        if ($item['status'] == -1) {
            return data_return_arr('任务已取消', 0);
        }
        if ($item['start_time'] > time()) {
            //需要延迟执行
            return data_return_arr('任务未开始', 0, ['delay' => intval($item['start_time'] - time())]);
        }
        $class = $item['class'];
        $method = $item['method'];
        if (!method_exists($class, $method) && !is_callable([$class, $method])) {
            (new TimerQueue())->update([
                'result' => '方法不存在或无法调用',
                'status' => 1,
                'try_count' => $item['try_count'] + 1,
                'real_time' => time(),
            ], ['id' => $item['id']]);
            cache($ckey, null);
            return data_return_arr('方法不存在或无法调用');
        }
        $item['param'] = self:: is_json($item['param']) ? @json_decode($item['param'], true) : $item['param'];

        try {
            $reflection = new \ReflectionMethod($item['class'], $item['method']);
        } catch (\ReflectionException $e) {
            bs_log($e->getTrace(), 'errc', 'err.log');
            bs_log($e->getMessage(), 'err', 'queue_diy_task.log');
            cache($ckey, null);

            (new TimerQueue())->update([
                'result' => $e->getMessage(),
                'status' => -2,//0=待执行，1=已完成，-1=已取消，-2=执行失败
                'try_count' => $item['try_count'] + 1,
                'real_time' => date('Y-m-d H:i:s'),
            ], ['id' => $id]);

            return data_return_arr($e->getMessage());
        }
        try {
            if ($reflection->isStatic()) {
                $res = $class::$method($item['param']);
            } else {
                $res = (new $class())->$method($item['param']);
            }
        } catch (\Throwable $e) {
            bs_log($e->getTrace(), 'errc', 'err.log');
            bs_log($e->getMessage(), 'err', 'queue_diy_task.log');
            cache($ckey, null);
            (new TimerQueue())->update([
                'result' => $e->getMessage(),
                'status' => -2,//0=待执行，1=已完成，-1=已取消，-2=执行失败
                'try_count' => $item['try_count'] + 1,
                'real_time' => date('Y-m-d H:i:s'),
            ], ['id' => $id]);
            return data_return_arr($e->getMessage());
        }

        $status = 1;//0=待执行，1=已完成，-1=已取消，-2=执行失败
        if (is_array($res)) {
            if (isset($res['code']) && $res['code'] !== 0) {
                $status = -2;
            } elseif (isset($res['status']) && $res['status'] != 0) {
                $status = -2;
            }
        }
        (new TimerQueue())->update([
            'result' => json_encode(is_array($res) ? $res : [$res], JSON_UNESCAPED_UNICODE),
            'status' => $status,//0=待执行，1=已完成，-1=已取消，-2=执行失败
            'try_count' => $item['try_count'] + 1,
            'real_time' => date('Y-m-d H:i:s'),
        ], ['id' => $id]);

        cache($ckey, null);
        return data_return_arr('执行成功', 0);
    }

    //判断是否是json
    private static function is_json($str): bool
    {
        if (is_string($str)) {
            $str = trim($str);
            if (substr($str, 0, 1) === '{' && substr($str, -1) === '}') {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }


    public function list($args = [])
    {
        $page = intval($args['page'] ?? 1);
        $pageSize = intval($args['limit'] ?? 10);
        $status = trim($args['status'] ?? '');

        $where = [];
        if (!empty($args['keyword'])) {
            $where[] = ['class|method', 'like', '%' . trim($args['keyword']) . '%'];
        }
        if (is_numeric($status)) {
            $where[] = ['status', '=', intval($status)];
        }
        $field = 'id,class,method,start_time,real_time,try_count,status,result,created_at,updated_at';
        $total = $this->model->data_count($where);

        $data = $this->model->data_list($where, $field, 'id desc', $page, $pageSize);
        if ($data) {
            foreach ($data as &$item) {
                $item['start_time'] = date('Y-m-d H:i:s', $item['start_time']);
                //0=待执行，1=已完成，-1=已取消，-2=执行失败
                $item['status_text'] = $item['status'] == -1 ? '已取消' : ($item['status'] == -2 ? '执行失败' : ($item['status'] == 1 ? '已完成' : '待执行'));
            }
            unset($item);
        }
        return $this->success_return('success', [
            'total' => $total,
            'list' => $data
        ]);
    }

    public function get($args = [])
    {
        $id = intval($args['id'] ?? 0);
        $data = $this->model->data_get(['id' => $id]);
        return $this->success_return('success', $data);
    }

    public function save_data($args): array
    {
        $id = intval($args['id'] ?? 0);
        $baseData = [
            'status' => $args['status'] ?? 1,
        ];
        if ($id) {
            $this->model->data_update(['id' => $id], $baseData);
        } else {
            $this->model->data_add($baseData);
        }
        return $this->success_return('保存成功');
    }

    public function del_data($args): array
    {
        $ids = $args['ids'] ?? [];
        if (!$ids) {
            return self::error_return('请选择要删除的任务');
        }
        $res = $this->model->data_del([['id', 'in', $ids]]);
        return $this->success_return('删除成功');
    }

    public function redo_job($args)
    {
        $ids = $args['ids'] ?? [];
        if (!$ids) {
            return self::error_return('请选择要重新执行的任务');
        }
        $data_list = $this->model->data_list_nopage([['id', 'in', $ids]]);
        if (!$data_list) {
            return self::error_return('任务不存在');
        }
        foreach ($data_list as $data) {
            $param = self::is_json($data['param']) ? @json_decode($data['param'], true) : $data['param'];
            $res = bs_queue($data['class'], $data['method'], $param, $data['start_time'], 2);
            if ($res) {
                $this->model->data_del(['id' => $data['id']]);
            }
        }

        return self::success_return('已重新执行');
    }
}
